Skip to main content

企业微信支付 发红包和给员工付款功能

前提:

企业微信官方提供的SDK中并没有企业微信支付这块的代码。

我的环境

我是用lumen框架进行开发的, 整个系统是用模块化的思想开发的。

介绍

1. 修改官方SDK代码

官方的SDK里面有一些错误的地方,比如静态方法里面用了$this 这些都要自己使用的时候去改过来。

我们用要改的地方是

文件 wework\app\SDK\weworkapi\api\src\CorpAPI.class.php

    static private function _HttpPostXml($url, $args)
{
$postData = Utils::Array2Xml("xml", $args);
$rspRawStr = HttpUtils::postXmlCurl( $postData,$url,true);
return Utils::Xml2Array($rspRawStr);
}

文件 \wework\app\SDK\weworkapi\utils\HttpUtils.class.php

    /**
* 以post方式提交xml到对应的接口url
*
* @param WxPayConfigInterface $config 配置对象
* @param string $xml 需要post的xml数据
* @param string $url url
* @param bool $useCert 是否需要证书,默认不需要
* @param int $second url执行超时时间,默认30s
* @throws WxPayException
*/
public static function postXmlCurl( $xml, $url, $useCert = false, $second = 30)
{
$ch = curl_init();
$curlVersion = curl_version();
$ua = "WXPaySDK/3 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." ".'1508124981';

//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);


curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验s
curl_setopt($ch,CURLOPT_USERAGENT, $ua);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

if($useCert == true){
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//证书文件请放入服务器的非web目录下
$sslCertPath = storage_path('cert'.DIRECTORY_SEPARATOR.'apiclient_cert.pem');
$sslKeyPath = storage_path('cert'.DIRECTORY_SEPARATOR.'apiclient_key.pem');
// dump($sslCertPath);
// dump($sslKeyPath);
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath);
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath);
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);

//返回结果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出错,错误码:$error");
}


}

2. 配置类 trait类

这是我的一个配置的trait类,这些写的好处是,可以在每个模块的Controller类中,使用构造函数初始化。 模块的各个类里面使用这些参数,

namespace App\Traits;

trait WorkConfig
{
protected $api;
protected $corpid;
protected $appid;
protected $agentid;
protected $redirect_uri;
protected $token;
protected $encodingAESKey;
protected $key;
}

下面是我封装的发红包和给员工付款功能代码。

<?php
/**
* Created by PhpStorm.
* User: 清行
* Date: 2020/3/9
* Time: 17:40
*/

namespace App\Http\Controllers\V1\Pay;

use App\Http\Controllers\V1\Contacts\UsersController;
use App\Http\Controllers\V1\Controller;
use App\Traits\WorkConfig;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use PayWwSptrans2PocketReq;
use SendWorkWxRedpackReq;


class PayController extends Controller
{
use WorkConfig;

public function __construct()
{
$this->corpid = config('wework.CORP_ID');
$this->agentid = config('wework.PAY_APP_ID');
$this->secret = config('wework.PAY_APP_SECRET');
$this->key = config('wework.PAY_APP_KEY');
$this->redirect_uri = 'https://work.tyunai.cn/api/oauth/user_info';
$url = base_path()."/app/SDK/weworkapi/api/src/CorpAPI.class.php";
include_once (str_ireplace('\\','/',$url));
$this->api = new \CorpAPI($this->corpid, $this->secret);
}

//发红包
public function sendWorkWxRedPack()
{
$user = new UsersController();
$openid = $user->convert_to_openid("PanYingJiaoJOJO");

Log::info($openid);

$SendWorkWxRedpackReq = new SendWorkWxRedpackReq();
{
$SendWorkWxRedpackReq->nonce_str = "nonce_str".time();
$SendWorkWxRedpackReq->mch_billno = "e123".time();
$SendWorkWxRedpackReq->mch_id = "1508124981";
$SendWorkWxRedpackReq->wxappid = $this->corpid;
$SendWorkWxRedpackReq->agentid = '1000122';//$this->agentid;
// $SendWorkWxRedpackReq->sender_name = "XX活动";
// $SendWorkWxRedpackReq->sender_header_media_id = config("wework.PAY_APP_ID");
$SendWorkWxRedpackReq->re_openid = $openid;
$SendWorkWxRedpackReq->total_amount = 101;
$SendWorkWxRedpackReq->wishing = "节日快乐";
$SendWorkWxRedpackReq->act_name = "猜灯谜抢红包活动";
$SendWorkWxRedpackReq->remark = "备注";
// $SendWorkWxRedpackReq->scene_id = "PRODUCT_2";
$SendWorkWxRedpackReq->workwx_sign = $this->getWorkwxSign($SendWorkWxRedpackReq,1);
$SendWorkWxRedpackReq->sign = $this->getSign($SendWorkWxRedpackReq);
}

$result = $this->api->SendWorkWxRedpack($SendWorkWxRedpackReq);
return $this->jsonSuccessData($result);
}

// 向员工付款
public function pay2user(Request $request)
{
$user = new UsersController();
$openid = $user->convert_to_openid("PanYingJiaoJOJO");

$PayWwSptrans2PocketReq = new PayWwSptrans2PocketReq();
{
$PayWwSptrans2PocketReq->appid = $this->corpid;
$PayWwSptrans2PocketReq->mch_id = "1508124981";
$PayWwSptrans2PocketReq->nonce_str = "sj03".rand(100,200);
$PayWwSptrans2PocketReq->partner_trade_no = time();
$PayWwSptrans2PocketReq->openid = $openid;
// $PayWwSptrans2PocketReq->check_name = 'NO_CHECK';
$PayWwSptrans2PocketReq->check_name = 'FORCE_CHECK';
$PayWwSptrans2PocketReq->re_user_name = '潘颖娇';
$PayWwSptrans2PocketReq->amount = '110';
$PayWwSptrans2PocketReq->desc = '付款说明';
$PayWwSptrans2PocketReq->spbill_create_ip = $request->getClientIp(); //'122.51.24.56';
$PayWwSptrans2PocketReq->ww_msg_type = 'NORMAL_MSG';
$PayWwSptrans2PocketReq->agentid = $this->agentid;
$PayWwSptrans2PocketReq->act_name = '开发部';
$PayWwSptrans2PocketReq->workwx_sign = $this->getWorkwxSign($PayWwSptrans2PocketReq,2);
$PayWwSptrans2PocketReq->sign = $this->getSign($PayWwSptrans2PocketReq);
}

$result = $this->api::PayWwSptrans2Pocket($PayWwSptrans2PocketReq);
return $this->jsonSuccessData($result);
}


/**
* 封装企业微信签名算法
* type 1 为红包 2为向员工付款
*/
public function getWorkwxSign($object,$type)
{
if ($type == 1)
{
$data =[
'act_name' => $object->act_name,
'mch_billno' => $object->mch_billno,
'mch_id' => $object->mch_id,
'nonce_str' => $object->nonce_str,
're_openid' => $object->re_openid,
'total_amount' => $object->total_amount,
'wxappid' => $object->wxappid,
];
}else if ($type == 2)
{
$data =[
'amount' => $object->amount,
'appid' => $object->appid,
'desc' => $object->desc,
'mch_id' => $object->mch_id,
'nonce_str' => $object->nonce_str,
'openid' => $object->openid,
'partner_trade_no' => $object->partner_trade_no,
'ww_msg_type' => $object->ww_msg_type,
];
}
ksort($data);
$stringA = $this->ToUrlParams( $data );
$workurl = $stringA.'&secret='.$this->secret;
$workwx_sign = strtoupper(md5($workurl));
return $workwx_sign;
}

/**
* 封装微信支付签名算法
* type 1 为红包 2为向员工付款
*/
public function getSign($object)
{
$data = array_filter(Object2Array($object));
ksort($data);
$stringA = $this->ToUrlParams( $data );
$wxurl = $stringA.'&key='.$this->key;
$sign = strtoupper(md5($wxurl));
return $sign;
}

/**
*
* 拼接签名字符串
* @param array $urlObj
*
* @return 返回已经拼接好的字符串
*/
private function ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v)
{
if($k != "sign"){
$buff .= $k . "=" . $v . "&";
}
}

$buff = trim($buff, "&");
return $buff;
}


}

签名的步骤太复杂,不去自己写的话,不知道会有这么多坑。 关键是官方的文档里写的还挺清楚,怪我没认真看。
好了。我用2天完成的,不知道你们会花费多久时间完成。